Skip to content

grpcreplay: reject oversized record size in readRecord to prevent OOM#67

Merged
jba merged 1 commit into
google:mainfrom
adilburaksen:fix/grpcreplay-oversize-record-oom
May 1, 2026
Merged

grpcreplay: reject oversized record size in readRecord to prevent OOM#67
jba merged 1 commit into
google:mainfrom
adilburaksen:fix/grpcreplay-oversize-record-oom

Conversation

@adilburaksen

Copy link
Copy Markdown
Contributor

Summary

readRecord() in grpcreplay/binary_format.go reads size as a raw uint32
from the replay file and passes it directly to make([]byte, size) with no
bounds check. A crafted 13-byte .grpc_replay file can trigger a 4 GB
allocation
in any program that calls grpcreplay.NewReplayer() on an
attacker-supplied file.

Vulnerable code (before this fix)

func (r *binaryReader) readRecord() ([]byte, error) {
    var size uint32
    binary.Read(r.r, binary.LittleEndian, &size)
    buf := make([]byte, size) // no bounds check: up to 4 GB

Trigger file (13 bytes)

Field Value
Magic RPCReplay (9 bytes)
size 0xffffffff (4 bytes LE)

Standalone reproducer output (size capped at 512 MB to avoid crashing the host):

[*] Crafted replay file: 13 bytes
[*] Encoded size: 0x20000000 (512 MB)
[*] TotalAlloc before parse: 0 MB
[*] TotalAlloc after parse:  512 MB (delta: +512 MB)
[!] VULNERABLE: 512 MB allocated from a 13-byte replay file.

Fix

Add maxRecordSize = 64 MiB constant (gRPC's own default max message size
is 4 MiB; 64 MiB is a generous upper bound) and reject records that exceed
it before allocation.

Testing

TestOversizeRecord in grpcreplay_test.go verifies that readRecord()
returns an error for an oversized size field without causing a large allocation.

readRecord() reads size as a raw uint32 from the replay file and passes
it directly to make([]byte, size) with no bounds check. A crafted 13-byte
.grpc_replay file with size=0xFFFFFFFF triggers a 4 GB allocation in any
program calling NewReplayer() on an attacker-supplied file.

Add maxRecordSize (64 MiB; gRPC default max message size is 4 MiB) and
reject records that exceed it before allocation.

Add TestOversizeRecord to prevent regression.
@jba jba merged commit 4e667a3 into google:main May 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants